home *** CD-ROM | disk | FTP | other *** search
- /*
- ** MacSND DataType
- **
- ** Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
- ** Public domain
- **
- ** :ts=4
- */
-
- #include "Global.h"
-
- // Maximum supported replay rate, as per the "Amiga Hardware Reference Manual"
-
- #define MAX_SAMPLE_RATE 28867
-
- // The minimum sample rate we will allow when scaling a sound down
-
- #define MIN_SAMPLE_RATE 5563
-
- // How many bytes to read in one piece
-
- #define MIN_FRAME_RATE (2048 * 8)
-
- /* ConvertSample(const UBYTE *Src,BYTE *Dst,LONG NumSamples,const LONG Skip):
- *
- * Convert the native Macintosh format sample data into plain
- * signed 8 bits/sample Amiga data
- */
-
- STATIC VOID __regargs
- ConvertSample(const UBYTE *Src,BYTE *Dst,LONG NumSamples,const LONG Skip)
- {
- LONG SkipCount;
- UBYTE Value;
-
- // Make sure that the first sample is converted
-
- SkipCount = 1;
-
- // Convert all the samples if possible
-
- while(NumSamples-- > 0)
- {
- // It's easy to convert a Macintosh sample :^)
-
- Value = *(Src++) ^ 0x80;
-
- // Store this sample value?
-
- if(--SkipCount < 1)
- {
- // Keep this sample
-
- *Dst++ = (BYTE)Value;
-
- // Skip the next samples if necessary
-
- SkipCount = Skip;
- }
- }
- }
-
- /* GetSND(Object *object,struct TagItem *Tags,struct ClassBase *ClassBase):
- *
- * Convert a Macintosh "snd " resource into a DataTypes object
- */
-
- STATIC BOOL __regargs
- GetSND(Object *object,struct TagItem *Tags,struct ClassBase *ClassBase)
- {
- struct VoiceHeader *VoiceHeader = NULL;
- BPTR File = NULL;
- LONG Error = 0;
- STRPTR Title = (STRPTR)GetTagData(DTA_Name,NULL,Tags);
- BOOL Result = FALSE;
-
- // Get the basic data
-
- GetDTAttrs(object,
- SDTA_VoiceHeader, &VoiceHeader,
- DTA_Handle, &File,
- TAG_DONE);
-
- // Do we have everything we need?
-
- if(File && VoiceHeader && Title)
- {
- BPTR FileHandle;
-
- // Open the file
-
- if(FileHandle = Open(Title,MODE_OLDFILE))
- {
- struct SoundDataHeader Header;
- BOOL GotIt = FALSE;
-
- // Add some cache
-
- SetVBuf(FileHandle,NULL,BUF_FULL,4096);
-
- // Read the MacBinary header if possible
-
- if(ReadMacBinaryHeader(FileHandle,&Error,SysBase,DOSBase))
- {
- // If it's a MacBinary format file, read the rest
-
- if(ScanResource(FileHandle,&Header,&Error,SysBase,DOSBase))
- GotIt = TRUE;
- }
-
- // So it's not a MacBinary format file
-
- if(!GotIt)
- {
- // Return to the beginning of the file
-
- if(Seek(FileHandle,0,OFFSET_BEGINNING) != -1)
- {
- // Look for "snd " resources
-
- if(ScanResource(FileHandle,&Header,&Error,SysBase,DOSBase))
- GotIt = TRUE;
- }
- }
-
- // Did we get anything?
-
- if(GotIt)
- {
- BYTE *Sample = NULL;
- UBYTE *Source;
- ULONG Memory;
- LONG Rate,Size,Skip,Frame;
-
- // Fill in the basic data
-
- Rate = Header . SampleRate;
- Size = Header . SampleSize;
- Skip = 1;
-
- // Don't waste too much memory for reading
-
- if(Header . SampleSize < MIN_FRAME_RATE)
- Frame = Header . SampleSize;
- else
- Frame = MIN_FRAME_RATE;
-
- // sound.datatype v40 no longer requires
- // the entire sample to reside in chip memory
-
- if(SuperClassBase -> lib_Version > 39)
- Memory = MEMF_ANY;
- else
- Memory = MEMF_CHIP;
-
- // Scale the sound down if the Amiga sound hardware
- // would be unable to handle the replay rate
-
- while(Size > 0 && Rate > MIN_SAMPLE_RATE && Rate > MAX_SAMPLE_RATE)
- {
- Size /= 2;
- Rate /= 2;
- Skip *= 2;
- }
-
- // Allocate the read buffer
-
- if(Source = AllocVec(Frame,MEMF_ANY))
- {
- // Try to allocate memory for the sample data
-
- while(!(Sample = AllocVec(Size,Memory | MEMF_CLEAR)) && Size > 0 && Rate > MIN_SAMPLE_RATE)
- {
- // Scale it down if necessary
-
- Size /= 2;
- Rate /= 2;
- Skip *= 2;
- }
-
- // Did we get anything?
-
- if(!Sample)
- Error = ERROR_NO_FREE_STORE;
- }
- else
- Error = ERROR_NO_FREE_STORE;
-
- // Did we get what we wanted?
-
- if(Sample && !Error)
- {
- BYTE *Dst = Sample;
- LONG Total = Header . SampleSize,
- Needed;
-
- // Read the source data
-
- while(!Error && Total > 0)
- {
- if(Frame > Total)
- Needed = Total;
- else
- Needed = Frame;
-
- if(Read(FileHandle,Source,Needed) == Needed)
- {
- // Convert the source data
-
- ConvertSample(Source,Dst,Needed,Skip);
-
- Total -= Needed;
- Dst += Needed;
- }
- else
- Error = IoErr();
- }
-
- // No read error so far?
-
- if(!Error)
- {
- BYTE Smallest,Largest;
- LONG i;
-
- // Initialize the voice header
-
- memset(VoiceHeader,0,sizeof(struct VoiceHeader));
-
- VoiceHeader -> vh_OneShotHiSamples = Size;
- VoiceHeader -> vh_SamplesPerSec = Rate;
- VoiceHeader -> vh_Octaves = 1;
- VoiceHeader -> vh_Compression = CMP_NONE;
- VoiceHeader -> vh_Volume = 64;
-
- // Look for the smallest and the largest
- // sample value
-
- Smallest = 127;
- Largest = -128;
- Dst = Sample;
-
- for(i = 0 ; i < Size ; i++)
- {
- if(Dst[i] < Smallest)
- Smallest = Dst[i];
-
- if(Dst[i] > Largest)
- Largest = Dst[i];
- }
-
- // Does it use the full range?
-
- if(Smallest > -128 || Largest < 127)
- {
- BYTE Table[256],*Index;
- WORD j;
-
- // Point it into the middle
-
- Index = &Table[128];
-
- // Scale the negative values
- // to use the full dynamic
- // amplitude range
-
- for(j = Smallest ; j < 0 ; j++)
- Index[j] = (-128 * j) / Smallest;
-
- // Cut off anything below the
- // smallest value
-
- for(j = -128 ; j < Smallest ; j++)
- Index[j] = -128;
-
- Index[0] = 0;
-
- // Scale the positive values
- // to use the full dynamic
- // amplitude range
-
- for(j = 1 ; j <= Largest ; j++)
- Index[j] = (127 * j) / Largest;
-
- // Cut off anything above the
- // largest value
-
- for(j = Largest + 1 ; j < 256 ; j++)
- Index[j] = 127;
-
- // Make the data use the full range
-
- Dst = Sample;
-
- for(i = 0 ; i < Size ; i++)
- Dst[i] = Index[Dst[i]];
- }
-
- // Fill in the remaining information
-
- SetDTAttrs(object,NULL,NULL,
- DTA_ObjName, Title,
- SDTA_Sample, Sample,
- SDTA_SampleLength, VoiceHeader -> vh_OneShotHiSamples,
- SDTA_Period, (ULONG)(SysBase -> ex_EClockFrequency * 5) / (ULONG)VoiceHeader -> vh_SamplesPerSec,
- SDTA_Volume, 64,
- SDTA_Cycles, 1,
- TAG_DONE);
-
- // Successful conversion
-
- Result = TRUE;
- }
- }
-
- // No success?
-
- if(Error)
- Result = FALSE;
-
- // Clean up...
-
- if(Source)
- FreeVec(Source);
-
- if(Sample && !Result)
- FreeVec(Sample);
- }
- else
- Error = ERROR_OBJECT_NOT_FOUND;
-
- Close(FileHandle);
- }
- else
- Error = IoErr();
- }
- else
- Error = ERROR_OBJECT_NOT_FOUND;
-
- // Set the error code
-
- if(Error)
- SetIoErr(Error);
-
- return(Result);
- }
-
- /* RealClassDispatch():
- *
- * The class dispatcher routine.
- */
-
- STATIC Object * __stdargs
- RealClassDispatch(Class *class,Object *object,Msg msg)
- {
- struct ClassBase *ClassBase = (struct ClassBase *)class -> cl_UserData;
- Object *Result;
-
- // What message is it?
-
- switch(msg -> MethodID)
- {
- // Create a new instance
-
- case OM_NEW:
-
- if(Result = (Object *)DoSuperMethodA(class,object,msg))
- {
- if(!GetSND(Result,((struct opSet *)msg) -> ops_AttrList,ClassBase))
- {
- CoerceMethod(class,Result,OM_DISPOSE);
-
- Result = NULL;
- }
- }
-
- break;
-
- // Let the superclass handle the rest
-
- default:
-
- Result = (Object *)DoSuperMethodA(class,object,msg);
-
- break;
- }
-
- return(Result);
- }
-
- /* ClassDispatch():
- *
- * The frontend to the real class dispatcher routine.
- */
-
- Object * __saveds __asm
- ClassDispatch(register __a0 Class *class,register __a2 Object *object,register __a1 Msg msg)
- {
- LONG Success;
-
- return((Object *)StackCall(&Success,8192,3,(LONG (* __stdargs)(...))RealClassDispatch,class,object,msg));
- }
-